﻿using GalaSoft.MvvmLight.Ioc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace MVVMLightLesson.Base
{
    public class MyIOC
    {
        #region 单例模式
        private static readonly object _instanceLock = new object();

        private static MyIOC _default;

        //
        // 摘要:
        //     This class' default instance.
        public static MyIOC Default
        {
            get
            {
                if (_default == null)
                {
                    lock (_instanceLock)
                    {
                        if (_default == null)
                        {
                            _default = new MyIOC();
                        }
                    }
                }

                return _default;
            }
        }

        private MyIOC()
        {
        }
        #endregion

        //Dictionary<string,Type> _objectsDic = new Dictionary<string, Type>();
        Dictionary<string, InstenceModel> _instanceDic = new Dictionary<string, InstenceModel>();

        ///// <summary>
        ///// 瞬时状态
        ///// </summary>
        ///// <typeparam name="T"></typeparam>
        //public void Register<T>()
        //{
        //    _instanceDic.Add(typeof(T).FullName!,
        //        new InstenceModel() { ObjectType = typeof(T), IsSinglton = false });//加感叹号表示不可能为null
        //}

        //public void Register<TFrom, TTo>() where TTo : TFrom
        //{
        //    _instanceDic.Add(typeof(TFrom).FullName!, new InstenceModel
        //    {
        //        ObjectType = typeof(TTo),
        //        IsSinglton = false
        //    });
        //}

        ///// <summary>
        ///// 单例状态
        ///// </summary>
        ///// <typeparam name="T"></typeparam>
        //public void RegisterSingle<T>()
        //{
        //    _instanceDic.Add(typeof(T).FullName!,
        //        new InstenceModel() { ObjectType = typeof(T), IsSinglton = true });//加感叹号表示不可能为null
        //}
        //public void RegisterSingle<TFrom, TTo>() where TTo : TFrom
        //{
        //    _instanceDic.Add(typeof(TFrom).FullName!, new InstenceModel
        //    {
        //        ObjectType = typeof(TTo),
        //        IsSinglton = true
        //    });
        //}

        // 瞬时状态
        public void Register<T>()
        {
            _instanceDic.Add(
                typeof(T).FullName!,
                new InstenceModel { ObjectType = typeof(T), IsSinglton = false });
        }
        // 单例状态
        public void RegisterSingle<T>()
        {
            _instanceDic.Add(
                typeof(T).FullName!,
                new InstenceModel { ObjectType = typeof(T), IsSinglton = true });
        }
        public void Register<TFrom, TTo>(string token = "") where TTo : TFrom
        {
            string key =
                typeof(TFrom).FullName +
                (String.IsNullOrEmpty(token) ? "" : "_#%%$#_" + token);//_#%%$#_没有特别的涵义  只是区分token

            _instanceDic.Add(
                key,
                new InstenceModel { ObjectType = typeof(TTo), IsSinglton = false });
        }
        public void RegisterSingle<TFrom, TTo>(string token = "") where TTo : TFrom
        {
            string key =
                typeof(TFrom).FullName +
                (String.IsNullOrEmpty(token) ? "" : "_#%%$#_" + token);

            _instanceDic.Add(
                key,
                new InstenceModel { ObjectType = typeof(TTo), IsSinglton = true });
        }

        //    public T Resolve<T>()
        //    {
        //        string key = typeof(T).FullName!;
        //        if (_objectsDic.ContainsKey(key))
        //        {
        //            return (T)Activator.CreateInstance(_objectsDic[key]);
        //        }
        //        return default(T)!;//返回默认值: return default(T); 如果字典中不包含该键，则返回类型 T 的默认值，若 T 是值类型则返回零值，若 T 是引用类型则返回 null。
        //    }

        //    public T ResolveSingle<T>()
        //    {
        //        string key = typeof(T).FullName!;
        //        if (_instanceDic.ContainsKey(key))
        //        {
        //            if (_instanceDic[key].Instence is null)// 如果为空，则创建实例
        //            {
        //                #region  检查构造函数的参数 如果有参数，根据类型动态创建实例                    
        //                ConstructorInfo[] constructors = _instanceDic[key].ObjectType.GetConstructors();//找到所有构造函数
        //                ParameterInfo[] parameters = constructors[0].GetParameters();//找到第一个构造函数的参数                                                                                
        //                List<object> objects = new List<object>(); // 参数列表
        //                foreach (ParameterInfo param in parameters)
        //                {
        //                    string paramKey = param.ParameterType.FullName;
        //                    if (_instanceDic.ContainsKey(paramKey))
        //                    {
        //                        if (_instanceDic[paramKey].Instence is null)
        //                            _instanceDic[paramKey].Instence =
        //                                Activator.CreateInstance(_instanceDic[paramKey].ObjectType);

        //                        objects.Add(_instanceDic[paramKey].Instence);
        //                    }
        //                    else
        //                        objects.Add(null);
        //                }
        //                #endregion
        //                // 创建对象实例，创建之前需要准备好这个对象的构造函数的参数
        //                var obj = Activator.CreateInstance(_instanceDic[key].ObjectType, objects.ToArray());
        //                _instanceDic[key].Instence = obj;
        //                return (T)obj;
        //            }
        //            return (T)_instanceDic[key].Instence;
        //        }
        //        return default(T)!;//返回默认值: return default(T); 如果字典中不包含该键，则返回类型 T 的默认值，若 T 是值类型则返回零值，若 T 是引用类型则返回 null。
        //    }
        //}

        public T Resolve<T>()
        {
            string key = typeof(T).FullName;
            if (_instanceDic.ContainsKey(key))
            {
                if (_instanceDic[key].IsSinglton)//如果是单例模式
                {
                    if (_instanceDic[key].Instence is null)//单例模式是否已经创建实例 如果不存在 则创建实例
                    {
                        lock (_instanceLock)
                        {
                            if (_instanceDic[key].Instence is null)
                            {
                                // 在单例模式下，之前没有创建实例的前提下调用
                                return (T)CreateInstence(key, typeof(T));
                            }
                            return (T)_instanceDic[key].Instence;
                        }
                    }
                    return (T)_instanceDic[key].Instence;//如果已经创建了实例，直接返回
                }
                else //如果不是单例模式  则每次创建实例
                {
                    // 在瞬时模式下，每次都调用
                    return (T)CreateInstence(key, typeof(T));
                }
            }
            return default(T);
        }

        private object CreateInstence(string key, Type type)
        {
            #region 检查构造函数的参数
            // 如果有参数，根据类型动态创建实例
            ConstructorInfo[] cis = _instanceDic[key].ObjectType.GetConstructors();
            ParameterInfo[] cpis = cis[0].GetParameters();
            // 参数列表
            List<object> objects = new List<object>();
            foreach (ParameterInfo cpi in cpis)
            {
                // AAA   MySqlDA.
                string paramTypeKey = cpi.ParameterType.FullName;
                if (cpi.IsDefined(typeof(DependyAttribute), false))
                {
                    var attr = cpi.GetCustomAttribute<DependyAttribute>();
                    paramTypeKey += string.IsNullOrEmpty(attr.Token) ? "" : "_#%%$#_" + attr.Token;
                }
                if (_instanceDic.ContainsKey(paramTypeKey))
                {
                    if (_instanceDic[paramTypeKey].IsSinglton)
                    {
                        if (_instanceDic[paramTypeKey].Instence is null)
                        {
                            //_instenceDic[paramTypeKey].Instence =
                            //    Activator.CreateInstance(_instenceDic[paramTypeKey].ObjectType);
                            _instanceDic[paramTypeKey].Instence =
                            CreateInstence(paramTypeKey, _instanceDic[paramTypeKey].ObjectType);//递归创建实例 MainViewModel -----> LoginBLL -----> MySqlDA
                        }
                    }
                    else
                    {
                        _instanceDic[paramTypeKey].Instence =
                            CreateInstence(paramTypeKey, _instanceDic[paramTypeKey].ObjectType);
                    }

                    objects.Add(_instanceDic[paramTypeKey].Instence);
                }
                else
                    objects.Add(null);
            }
            #endregion


            // 创建对象实例，创建之前需要准备好这个对象的构造函数的参数
            var obj = Activator.CreateInstance(_instanceDic[key].ObjectType, objects.ToArray());
            _instanceDic[key].Instence = obj;


            #region 检查属性的注入
            // 
            // 哪些属性需要注入   可以通过特性进行区分
            PropertyInfo[] pis = type.GetProperties();//反射出类型中的所有属性
            //type.GetFields();// 获取所有字段
            foreach (var pi in pis)
            {
                // 判断属性上是否有特定标记，如果有，实例化这个属性
                if (pi.IsDefined(typeof(DependyAttribute), false))//如果说属性上面有DependyAttribute特性，那么就按照DependyAttribute的Token来注入
                {
                    var attr = pi.GetCustomAttribute<DependyAttribute>();

                    // 属性注入的时候   
                    string paramTypeKey = pi.PropertyType.FullName +
                        (string.IsNullOrEmpty(attr.Token) ? "" : "_#%%$#_" + attr.Token);

                    if (_instanceDic.ContainsKey(paramTypeKey))
                    {
                        if (_instanceDic[paramTypeKey].IsSinglton)
                        {
                            if (_instanceDic[paramTypeKey].Instence is null)
                            {
                                _instanceDic[paramTypeKey].Instence =
                                CreateInstence(paramTypeKey, _instanceDic[paramTypeKey].ObjectType);
                            }
                        }
                        else
                        {
                            _instanceDic[paramTypeKey].Instence =
                                CreateInstence(paramTypeKey, _instanceDic[paramTypeKey].ObjectType);
                        }

                        // 如果已经创建了实例，设置给当前对象的对应属性
                        // 第一个参数，指这个值要设置给哪个对象实例的这个属性
                        pi.SetValue(obj, _instanceDic[paramTypeKey].Instence);
                    }
                }
            }
            #endregion
            return obj;
        }

        /// <summary>
        /// 既要管理类型 也要管理实例  所以字典里面要增加一个class
        /// </summary>
        class InstenceModel
        {
            /// <summary>
            /// 是否是单例
            /// </summary>
            public bool IsSinglton { get; set; }
            public Type ObjectType { get; set; }
            public object Instence { get; set; }
        }
    }
}
